# ~*~ coding: utf-8 ~*~

from flask import request, url_for, session
from flask_login import current_user, logout_user
from flask import views, render_template
from sqlalchemy import or_

from apps.common.response import params_error, success, auth_error
from apps.extensions import db, cache
from apps.perms.mixin import LoginRequiredMixin
from ..models import User
from ..forms import UserCheckPasswordForm, UserCheckOtpCodeForm
from ..utils import generate_otp_uri, check_otp_code


__all__ = ['UserOtpEnableAuthenticationView', 'UserOtpEnableInstallAppView',
           'UserOtpEnableBindView', 'UserOtpEnableSuccessView',
           'UserOtpDisableUnbindView', 'UserOtpDisableSuccessView']


class UserOtpEnableAuthenticationView(LoginRequiredMixin, views.MethodView):

    def get(self):
        return render_template('users/otp/user_password_authentication.html')

    def post(self):
        form = UserCheckPasswordForm(request.form)
        if form.validate_on_submit():
            user = db.session.query(User). \
                filter(or_(User.username == current_user.username, User.phone == current_user.username)). \
                first()
            if user.check_password(form.password.data.strip()):
                session['otp_authentication'] = True
                return success()
            else:
                return auth_error(data={
                    'message': '用户名或密码错误'
                })
        else:
            return params_error(data=form.get_error())


class UserOtpEnableInstallAppView(LoginRequiredMixin, views.MethodView):

    def get(self):
        return render_template('users/otp/user_otp_enable_install_app.html')


class UserOtpEnableBindView(LoginRequiredMixin, views.MethodView):

    def dispatch_request(self, *args, **kwargs):
        if session.get('otp_authentication', False):
            return super().dispatch_request(*args, **kwargs)
        else:
            return render_template('500.html')

    def get(self):
        otp_uri, otp_secret_key = generate_otp_uri()
        context = {
            'otp_uri': otp_uri,
            'otp_secret_key': otp_secret_key,
        }
        return render_template('users/otp/user_otp_enable_bind.html', **context)

    def post(self):
        form = UserCheckOtpCodeForm(request.form)
        if form.validate_on_submit():
            otp_code = form.otp_code.data.strip()
            otp_secret_key = cache.get('{}_{}'.format('otp_key', current_user.id))
            if check_otp_code(otp_secret_key, otp_code):
                current_user.enable_otp(otp_secret_key)
                current_user.update()
                session['otp_authentication'] = False
                return success()
            else:
                return auth_error(data={
                    'message': 'MFA验证码不正确，或者服务器端时间不对'
                })
        else:
            return params_error(data=form.get_error())


class UserOtpEnableSuccessView(LoginRequiredMixin, views.MethodView):

    def get(self):
        context = {
            'interval': 5,
            'messages': '绑定成功',
            'redirect_url': url_for('users.login')
        }
        logout_user()
        return render_template('users/otp/user_otp_enable_success.html', **context)


class UserOtpDisableUnbindView(LoginRequiredMixin, views.MethodView):
    def get(self):
        return render_template('users/otp/user_otp_disable_unbind.html')

    def post(self):
        form = UserCheckOtpCodeForm(request.form)
        if form.validate_on_submit():
            otp_code = form.otp_code.data.strip()
            otp_secret_key = current_user.otp_secret_key
            if check_otp_code(otp_secret_key, otp_code):
                current_user.disable_otp()
                current_user.update()
                return success()
            else:
                return auth_error(data={
                    'message': 'MFA验证码不正确，或者服务器端时间不对'
                })
        else:
            return params_error(data=form.get_error())


class UserOtpDisableSuccessView(LoginRequiredMixin, views.MethodView):

    def get(self):
        context = {
            'interval': 5,
            'messages': '解绑成功',
            'redirect_url': url_for('users.login')
        }
        logout_user()
        return render_template('users/otp/user_otp_disable_success.html', **context)
